﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews.Application
{
    using System;
    using System.Runtime.InteropServices;

    /// <summary>Provides access to native methods.</summary>
    internal static class NativeMethods
    {
        /// <summary>See <a href="http://msdn.microsoft.com/en-us/library/aa929753.aspx">SHFILEINFO</a>.</summary>
        internal struct SHFILEINFO
        {
            internal readonly IntPtr hIcon;
            internal readonly int iIcon;
            internal readonly uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            internal readonly string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            internal readonly string szTypeName;
        }

        [Flags]
        internal enum SHGFI : uint
        {
            SMALLICON = 0x000000001,
            USEFILEATTRIBUTES = 0x000000010,
            ICON = 0x000000100,
            LINKOVERLAY = 0x000008000
        }

        [DllImport("coredll.dll")]
        internal static extern IntPtr SHGetFileInfo(
            string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, SHGFI uFlags);

        [DllImport("coredll.dll")]
        internal static extern IntPtr ExtractIconEx(
            string lpszFile, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons);

        // We're deliberately ignoring errors, as we can't really do anything about them anyway.
        [DllImport("coredll.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern void DestroyIcon(IntPtr hIcon);

        [Flags]
        internal enum CONNMGR_FLAG_PROXY : uint
        {
            NONE = 0x0,
            HTTP = 0x1,
            WAP = 0x2,
            SOCKS4 = 0x4,
            SOCKS5 = 0x8
        }

        /// <summary>See <a href="http://msdn.microsoft.com/en-us/library/bb416390.aspx">CONNMGR_CONNECTIONINFO</a>.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        internal sealed class CONNMGR_CONNECTIONINFO
        {
            private readonly uint cbSize;
            private readonly CONNMGR_PARAM dwParams;
            private readonly CONNMGR_FLAG_PROXY dwFlags;
            private readonly CONNMGR_PRIORITY dwPriority;
            private readonly int bExclusive;
            private readonly int bDisabled;
            private readonly Guid guidDestNet;
            private readonly IntPtr hWnd;
            private readonly uint uMsg;
            private readonly int lParam;
            private readonly uint ulMaxCost;
            private readonly uint ulMinRcvBw;
            private readonly uint ulMaxConnLatency;

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            internal CONNMGR_CONNECTIONINFO(CONNMGR_FLAG_PROXY proxy, Guid destination)
            {
                this.cbSize = (uint)Marshal.SizeOf(typeof(CONNMGR_CONNECTIONINFO));
                this.dwParams = CONNMGR_PARAM.GUIDDESTNET;
                this.dwFlags = proxy;
                this.dwPriority = CONNMGR_PRIORITY.HIPRIBKGND;
                this.guidDestNet = destination;
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            [Flags]
            private enum CONNMGR_PARAM : uint
            {
                GUIDDESTNET = 0x1,
                MAXCOST = 0x2,
                MINRCVBW = 0x4,
                MAXCONNLATENCY = 0x8
            }

            [Flags]
            private enum CONNMGR_PRIORITY : uint
            {
                USERINTERACTIVE = 0x08000,
                HIPRIBKGND = 0x0200,
                LOWBKGND = 0x0008
            }
        }

        [DllImport("cellcore.dll", PreserveSig = false)]
        internal static extern void ConnMgrMapURL(string pwszURL, out Guid pguid, uint pdwIndex);

        [DllImport("cellcore.dll")]
        internal static extern int ConnMgrEstablishConnectionSync(
            CONNMGR_CONNECTIONINFO pConnInfo,
            out IntPtr phConnection,
            uint dwTimeout,
            out NetworkConnectionStatus pdwStatus);

        // We're deliberately ignoring errors, as we can't really do anything about them anyway.
        [DllImport("cellcore.dll")]
        internal static extern void ConnMgrReleaseConnection(IntPtr hConnection, int lCache);

        /// <summary>See <a href="http://msdn.microsoft.com/en-us/library/aa924534.aspx">DATA_BLOB</a>.</summary>
        [StructLayout(LayoutKind.Sequential)]
        internal sealed class DATA_BLOB : IDisposable
        {
            private uint cbData;
            private IntPtr pbData;

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            /// <summary>See <see cref="IDisposable.Dispose"/>.</summary>
            public void Dispose()
            {
                this.PrivateDispose();
                GC.SuppressFinalize(this);
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            internal DATA_BLOB()
            {
            }

            internal DATA_BLOB(byte[] data)
            {
                if (data != null)
                {
                    this.cbData = (uint)data.Length;
                    this.pbData = Marshal.AllocHGlobal(data.Length);
                    Marshal.Copy(data, 0, this.pbData, (int)this.cbData);
                }
            }

            internal byte[] Data
            {
                get
                {
                    if (this.pbData == IntPtr.Zero)
                    {
                        return null;
                    }
                    else
                    {
                        byte[] data = new byte[this.cbData];
                        Marshal.Copy(this.pbData, data, 0, (int)this.cbData);
                        return data;
                    }
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            ~DATA_BLOB()
            {
                this.PrivateDispose();
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            private void PrivateDispose()
            {
                Marshal.FreeHGlobal(this.pbData);
                this.cbData = 0;
                this.pbData = IntPtr.Zero;
            }
        }

        [DllImport("coredll.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool CryptProtectData(
            DATA_BLOB pDataIn,
            string pszDataDescr,
            DATA_BLOB pOptionalEntropy,
            IntPtr pvReserved,
            IntPtr pPromptStruct,
            uint dwFlags,
            DATA_BLOB pDataOut);

        [DllImport("coredll.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool CryptUnprotectData(
            DATA_BLOB pDataIn,
            string ppszDataDescr,
            DATA_BLOB pOptionalEntropy,
            IntPtr pvReserved,
            IntPtr pPromptStruct,
            uint dwFlags,
            DATA_BLOB pDataOut);
    }
}
